/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or https://opensource.org/licenses/CDDL-1.0.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_ZFS_CONTEXT_OS_H
#define	_SYS_ZFS_CONTEXT_OS_H

#include <time.h>
#include <sys/zfs_util.h>
#include <sys/nvpair.h>
#include "zfs.h"

#define	____cacheline_aligned

#ifndef zfs_fallthrough
#ifdef __GNUC__
#if __GNUC__ > 6
#define	zfs_fallthrough	__attribute__((__fallthrough__))
#else
#define	zfs_fallthrough	((void)0)
#endif	/* __GNUC__ > 6 */
#endif	/* __GNUC__ */
#endif	/* zfs_fallthrough */

typedef int fstrans_cookie_t;

static inline fstrans_cookie_t
spl_fstrans_mark(void) 
{
	return (0);
}

static inline void
spl_fstrans_unmark(fstrans_cookie_t x)
{
	(void) x;
}

/*
 * From libspl/time.h
 */

#ifndef SEC
#define	SEC		1
#endif

#ifndef MILLISEC
#define	MILLISEC	1000
#endif

#ifndef MICROSEC
#define	MICROSEC	1000000
#endif

#ifndef NANOSEC
#define	NANOSEC		1000000000
#endif

#ifndef NSEC_PER_USEC
#define	NSEC_PER_USEC	1000L
#endif

#ifndef MSEC2NSEC
#define	MSEC2NSEC(m)	((hrtime_t)(m) * (NANOSEC / MILLISEC))
#endif

#ifndef NSEC2MSEC
#define	NSEC2MSEC(n)	((n) / (NANOSEC / MILLISEC))
#endif

#ifndef USEC2NSEC
#define	USEC2NSEC(m)	((hrtime_t)(m) * (NANOSEC / MICROSEC))
#endif

#ifndef NSEC2USEC
#define	NSEC2USEC(n)	((n) / (NANOSEC / MICROSEC))
#endif

#ifndef NSEC2SEC
#define	NSEC2SEC(n)	((n) / (NANOSEC / SEC))
#endif

#ifndef SEC2NSEC
#define	SEC2NSEC(m)	((hrtime_t)(m) * (NANOSEC / SEC))
#endif

typedef	long long		hrtime_t;
typedef	struct timespec		timespec_t;
typedef struct timespec		inode_timespec_t;

static inline void
gethrestime(inode_timespec_t *ts)
{
	struct timeval tv;
	(void) gettimeofday(&tv, NULL);
	ts->tv_sec = tv.tv_sec;
	ts->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
}

static inline uint64_t
gethrestime_sec(void)
{
	struct timeval tv;
	(void) gettimeofday(&tv, NULL);
	return (tv.tv_sec);
}

/*
static inline hrtime_t
gethrtime(void)
{
	struct timespec ts;
	(void) clock_gettime(CLOCK_MONOTONIC, &ts);
	return ((((u_int64_t)ts.tv_sec) * NANOSEC) + ts.tv_nsec);
}
*/

/*
 * Os specific
 */

/*
 * We use the comma operator so that this macro can be used without much
 * additional code.  For example, "return (EINVAL);" becomes
 * "return (SET_ERROR(EINVAL));".  Note that the argument will be evaluated
 * twice, so it should not have side effects (e.g. something like:
 * "return (SET_ERROR(log_error(EINVAL, info)));" would log the error twice).
 */

extern void __set_error(const char *file, const char *func, int line, int err);
#define SET_ERROR(err) \
	(__set_error(__FILE__, __func__, __LINE__, err), err)

/*
 * Exported symbols
 */
#define	EXPORT_SYMBOL(x)

#define	ZFS_MODULE_DESCRIPTION(s)
#define	ZFS_MODULE_AUTHOR(s)
#define	ZFS_MODULE_LICENSE(s)
#define	ZFS_MODULE_VERSION(s)

extern vmem_t *zio_arena;
#define	vmem_qcache_reap(_v)		/* nothing */
#define	zio_arena_cache_reap_now()	/* nothing */

/*
 * vnodes
 */
typedef void vnode_t;

#define	vn_remove(path, x1, x2)		remove(path)
#define	vn_rename(from, to, seg)	rename((from), (to))

extern vnode_t *rootdir;

/*
 * Cyclic information
 */
typedef uintptr_t cyclic_id_t;
typedef uint16_t cyc_level_t;
typedef void (*cyc_func_t)(void *);

#define	CY_LOW_LEVEL	0
#define	CY_INFINITY	INT64_MAX
#define	CYCLIC_NONE	((cyclic_id_t)0)

typedef struct cyc_time {
	hrtime_t cyt_when;
	hrtime_t cyt_interval;
} cyc_time_t;

typedef struct cyc_handler {
	cyc_func_t cyh_func;
	void *cyh_arg;
	cyc_level_t cyh_level;
} cyc_handler_t;

extern cyclic_id_t cyclic_add(cyc_handler_t *, cyc_time_t *);
extern void cyclic_remove(cyclic_id_t);
extern int cyclic_reprogram(cyclic_id_t, hrtime_t);

/*
 * Buf structure
 */
#define	B_BUSY		0x0001
#define	B_DONE		0x0002
#define	B_ERROR		0x0004
#define	B_READ		0x0040	/* read when I/O occurs */
#define	B_WRITE		0x0100	/* non-read pseudo-flag */

typedef struct buf {
	int	b_flags;
	size_t	b_bcount;
	union {
		caddr_t b_addr;
	} b_un;

	lldaddr_t	_b_blkno;
#define	b_lblkno	_b_blkno._f
	size_t	b_resid;
	size_t	b_bufsize;
	int	(*b_iodone)(struct buf *);
	int	b_error;
	void	*b_private;
} buf_t;

extern void bioinit(buf_t *);
extern void biodone(buf_t *);
extern void bioerror(buf_t *, int);
extern int geterror(buf_t *);

extern int sysevent_post_event(const char *event_class,
    const char *event_subclass, const char *vendor, const char *pub_name,
    nvlist_t *attr_list, sysevent_id_t *eid);

#define	HAVE_LARGE_STACKS	1

#endif /* _SYS_ZFS_CONTEXT_OS_H */
